unit uMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls,
  GLScene, GLSimpleNavigation, GLObjects, GLCoordinates, GLCadencer, GLContext,
  GLWin32Viewer, GLCrossPlatform, BaseClasses, GLHUDObjects, VectorGeometry,
  AsyncTimer, GLWindowsFont, GLBitmapFont, GLRenderContextInfo,
  Checkers.Visualizer,
  Checkers.Cell,
  Checkers.Utils,
  Checkers.Renderer,
  Checkers.MoveQuee;

type
  TCheckersForm = class(TForm)
    MainScene: TGLScene;
    MainLight: TGLLightSource;
    GUI: TGLDummyCube;
    FPSText: TGLHUDText;
    MainFont: TGLWindowsBitmapFont;
    MainCadencer: TGLCadencer;
    FPSCounter: TGLDirectOpenGL;
    MainViewer: TGLSceneViewer;
    ViewerSplitter: TSplitter;
    Panel1: TPanel;
    Label1: TLabel;
    Sizes: TRadioGroup;
    GroupBox1: TGroupBox;
    GroupBox2: TGroupBox;
    Antialiasing: TListBox;
    MakeScreenshot: TButton;
    Speed: TTrackBar;
    LimitCadencer: TCheckBox;
    RemoveChecker: TButton;
    DefaultBoard: TButton;
    TestQuee: TButton;
    UseShaders: TCheckBox;
    IsFlipped: TCheckBox;
    IsReversed: TCheckBox;
    ReverseColors: TCheckBox;
    ShowLabels: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure SizesClick(Sender: TObject);
    procedure MainViewerMouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure AntialiasingMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MainViewerMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure IsFlippedClick(Sender: TObject);
    procedure IsReversedClick(Sender: TObject);
    procedure MakeScreenshotClick(Sender: TObject);
    procedure SpeedChange(Sender: TObject);
    procedure LimitCadencerClick(Sender: TObject);
    procedure RemoveCheckerClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure DefaultBoardClick(Sender: TObject);
    procedure UseShadersClick(Sender: TObject);
    procedure OnBoardReversed(Sender: TObject);
    procedure FPSCounterRender(Sender: TObject; var rci: TRenderContextInfo);
    procedure MainCadencerProgress(Sender: TObject;
      const deltaTime, newTime: Double);
    procedure TestQueeClick(Sender: TObject);
    procedure ShowLabelsClick(Sender: TObject);
    procedure ReverseColorsClick(Sender: TObject);
  public
    procedure OnSplitterMove(Sender: TObject);
    function MoveChecker(const AOldID, ANewID: Integer): Boolean;
    procedure OnQueeMoveComplete(Sender: TObject);
    procedure OnQueeComplete(Sender: TObject);
    procedure OnQueeInterrupted(Sender: TObject);
  private
  end;

var
  CheckersForm: TCheckersForm;
  vCheckers: TCheckersVisualizer;
  vAntialiasingCaption: Array [0 .. Integer(High(TGLAntiAliasing))
    ] of String = ('aaDefault', 'aaNone', 'aa2x', 'aa2xHQ', 'aa4x', 'aa4xHQ',
    'aa6x', 'aa8x', 'aa16x', 'csa8x', 'csa8xHQ', 'csa16x', 'csa16xHQ');
  // Array[0..72] of Integer = TBoard instance - look at "type" section in
  // Checkers.Visualizer.
  vTestBoard: Array [0 .. 72] of Integer;
  vSelectedCell: TCell;
  vColors: Array [0 .. 3] of TColor = (
    clRed,
    clAqua,
    clHighlight,
    clYellow
  );
  vQuee: TMoveQuee;

implementation

{$R *.dfm}

procedure TCheckersForm.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  // Test field
  vCheckers := TCheckersVisualizer.Create(MainViewer, MainScene);
  Speed.Position := 3;
  for i := 0 to 11 do
    vTestBoard[i] := 1;
  for i := 20 to 31 do
    vTestBoard[i] := -1;
  for i := 32 to 71 do
    vTestBoard[i] := -1;
  vCheckers.Board := TDrawBoard(vTestBoard);
  // Listening for board revers, if camera is to far from default position
  vCheckers.OnRevers := OnBoardReversed;
  // Light setup. Multilighting can be used in FFP mode.
  MainLight.MoveTo(vCheckers.Camera);
  MainLight.Position.SetPoint(0, 0, 0);
  // Demo features
  GUI.MoveLast;
  for i := 0 to Integer(High(TGLAntiAliasing)) do
    Antialiasing.AddItem(vAntialiasingCaption[i], nil);
  Antialiasing.ItemIndex := Integer(MainViewer.Buffer.Antialiasing);

  ViewerSplitter.OnMoved := OnSplitterMove;

  vQuee := TMoveQuee.Create;
  // Quee listeners
  vCheckers.OnQueeMoveComplete := OnQueeMoveComplete;
  vCheckers.OnQueeComplete := OnQueeComplete;
  vCheckers.OnQueeInterrupted := OnQueeInterrupted;
end;

procedure TCheckersForm.FormResize(Sender: TObject);
begin
  // Notification of size's change will be sended to TBackground instance
  vCheckers.NotifySizeChange(MainViewer.Width, MainViewer.Height)
end;

procedure TCheckersForm.FPSCounterRender(Sender: TObject;
  var rci: TRenderContextInfo);
begin
  FPSText.Text := MainViewer.FramesPerSecondText(0);
end;

procedure TCheckersForm.ShowLabelsClick(Sender: TObject);
begin
  vCheckers.ShowText := ShowLabels.Checked;
end;

procedure TCheckersForm.DefaultBoardClick(Sender: TObject);
begin
  vCheckers.Board := TDrawBoard(vTestBoard);
end;

procedure TCheckersForm.IsFlippedClick(Sender: TObject);
begin
  vCheckers.IsFlipped := IsFlipped.Checked;
end;

procedure TCheckersForm.IsReversedClick(Sender: TObject);
begin
  vCheckers.IsReversed := IsReversed.Checked;
  // MainViewer.Invalidate;
end;

procedure TCheckersForm.AntialiasingMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  MainViewer.Buffer.Antialiasing := TGLAntiAliasing(Antialiasing.ItemIndex);
end;

procedure TCheckersForm.MainCadencerProgress(Sender: TObject;
  const deltaTime, newTime: Double);
begin
  // MainViewer.Invalidate;
end;

procedure TCheckersForm.MainViewerMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  vNewCell: TCell;
begin
  // Using left mouse button for selection
  if ssLeft in Shift then
  begin
    vCheckers.ClearHighlites;
    vNewCell := vCheckers.RaycastOnCoords(X, Y);
    // Cell existanse check(it can be NIL in case of wrong picking - at white
    // cell or background, for example).
    if Assigned(vNewCell) then
    begin
      vCheckers.Highlites[vNewCell.ID] := (vColors[Random(Length(vColors))]);
      if Assigned(vSelectedCell) then
        // Will not move if there is a checker in a targeted cell
        if vCheckers.Checkers[vNewCell.ID] = nil then
        begin
          // Starting movement animation or exiting if there are any wrong
          // conditions(see TCheckersVisualizer.MoveChecker for a details)
          if not vCheckers.MoveChecker(vSelectedCell.ID, vNewCell.ID) then
            Exit;
          // Setting a move source decal at position of moving checker
          vCheckers.MarkMoveSource(vSelectedCell);
          vCheckers.MarkMoveTarget(vNewCell);
        end;
      vSelectedCell := vNewCell;
    end;
  end;
end;

procedure TCheckersForm.MainViewerMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var
  vCell: TCell;
begin
  // Cells picking example
  vCell := vCheckers.RaycastOnCoords(X, Y);
  if vCell <> nil then
    vCheckers.SelectCell(vCell);
end;

procedure TCheckersForm.MakeScreenshotClick(Sender: TObject);
begin
  vCheckers.SaveToFile('Screenshots\0.bmp', 256);
end;

function TCheckersForm.MoveChecker(const AOldID, ANewID: Integer): Boolean;
begin
  Result := vCheckers.MoveChecker(AOldID - 1, ANewID - 1);
end;

procedure TCheckersForm.OnBoardReversed(Sender: TObject);
begin
  IsReversed.Checked := vCheckers.IsReversed;
end;

procedure TCheckersForm.OnQueeComplete(Sender: TObject);
begin
{
  ShowMessage('Quee was completed. Quee tag = ' +
  IntToStr(TMoveQuee(Sender).Tag));
}
end;

procedure TCheckersForm.OnQueeInterrupted(Sender: TObject);
begin
{
  ShowMessage('Quee was interrupted on move ' +
  IntToStr(TQueeElement(Sender).Index));
}
end;

procedure TCheckersForm.OnQueeMoveComplete(Sender: TObject);
{var
  vMove:TQueeElement;
  vType:Integer;
  function BoolToString(AValue:Boolean):String;
  begin
    if AValue then
      Result := 'True'
    else
      Result := 'False';
  end; }
begin
{  vMove := TQueeElement(Sender);
  ShowMessage('Quee move was completed. Move ID = ' +
    IntToStr(vMove.Index) + '. Need to upgrade = ' + BoolToString(vMove.Upgrade));}
end;

procedure TCheckersForm.OnSplitterMove(Sender: TObject);
begin
  vCheckers.NotifySizeChange(MainViewer.Width, MainViewer.Height);
end;

procedure TCheckersForm.RemoveCheckerClick(Sender: TObject);
begin
  if Assigned(vSelectedCell) then
    vCheckers.RemoveChecker(vSelectedCell.ID);
end;

procedure TCheckersForm.ReverseColorsClick(Sender: TObject);
begin
  vCheckers.ReversedColors := ReverseColors.Checked;
end;

procedure TCheckersForm.SizesClick(Sender: TObject);
begin
  // Changing the size of a board(see TBoardSize enum for a details)
  vCheckers.Size := TBoardSize(Sizes.ItemIndex);
end;

procedure TCheckersForm.SpeedChange(Sender: TObject);
begin
  vCheckers.CheckerSpeed := Speed.Position;
end;

procedure TCheckersForm.TestQueeClick(Sender: TObject);
begin
  vQuee.Add(0, 15, 0, True);
  vQuee.Add(15, 17, 1, False);
  vCheckers.MoveQuee(vQuee);
end;

procedure TCheckersForm.UseShadersClick(Sender: TObject);
begin
  CheckersRenderer.UseShaders := UseShaders.Checked;
  // Manual viewer invalidation is required for switching from backbuffer
  MainViewer.Invalidate;
end;

procedure TCheckersForm.LimitCadencerClick(Sender: TObject);
begin
  if LimitCadencer.Checked then
  begin
    MainCadencer.MaxDeltaTime := 0.01;
    MainCadencer.FixedDeltaTime := 0.01;
  end
  else
  begin
    MainCadencer.MaxDeltaTime := 0;
    MainCadencer.FixedDeltaTime := 0;
  end;
end;

procedure TCheckersForm.FormDestroy(Sender: TObject);
begin
  MainCadencer.Enabled := False;
  vCheckers.Free;
end;

end.
